home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
WINDOWS
/
PROFFT.ARJ
/
COMPWIN.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-29
|
39KB
|
1,196 lines
/****************************************************************************
COMPWIN.CPP Denne filen inneholder (i denne rekkef°lgen):
*****************************************************************************
void TComplexWindow::TComplexWindow(PTWindowsObject AParent,
LPSTR lpszCaption, HANDLE hComplexPict, BITMAPINFO *bmpInfo,
HANDLE hBitmap) : TGenericPicWindow (AParent, lpszCaption,
bmpInfo, hBitmap)
TComplexWindow::~TComplexWindow()
void TComplexWindow::GetWindowClass(WNDCLASS& wc)
LPSTR TComplexWindow::GetClassName()
void TComplexWindow::WMSetCursor(RTMessage Msg)
void TComplexWindow::CopyComplex(HANDLE hSource, HANDLE hTarget)
BOOL TComplexWindow::ConvertComplexToBMP(HANDLE hTempComplex, HANDLE hNewBitmap)
BOOL TComplexWindow::MakeComplexConjugate(HANDLE hComp)
BOOL TComplexWindow::InvertSignCheckerboard(HANDLE hComp)
void TComplexWindow::PerformIFFT()
void TComplexWindow::PerformFFT()
BOOL TComplexWindow::FFT(HANDLE hTarget)
BOOL TComplexWindow::ConvertBMPToComplex(HANDLE hSourceBitmap, HANDLE hTargetComplex)
BOOL TComplexWindow::UpdateBitmap()
void TComplexWindow::Paint(HDC, PAINTSTRUCT& PaintInfo)
BOOL TComplexWindow::LockComplex()
void TComplexWindow::UnlockComplex()
void TComplexWindow::WMMDIActivate(RTMessage Msg)
void TComplexWindow::SetMenuItems(WORD wStatus)
void TComplexWindow::PrepareToExecuteFilter()
void TComplexWindow::ExecuteFilter(HDC hdcMem)
****************************************************************************/
#include <owl.h>
#include <stdlib.h>
#include <stdio.h>
#include <filedial.h>
#include <static.h>
#include <dir.h>
#include <dos.h>
#include <string.h>
#include <mem.h>
#include <math.h>
#pragma hdrstop
#include "profftid.h" // Symbolske konstanter
#include "profft.h" // Klassedefinisjoner
#include "prcomp.h" // Kompleks struktur + komplekse konst.
void TComplexWindow::TComplexWindow(PTWindowsObject AParent,
LPSTR lpszCaption, HANDLE hComplexPict, BITMAPINFO *bmpInfo,
HANDLE hBitmap) : TGenericPicWindow (AParent, lpszCaption,
bmpInfo, hBitmap, FALSE)
/****************************************************************************
Konstruktoren til TComplexWindow setter opp en del standardverdier og
klargj°r noen ressurser som skal brukes i dette objektet. Noen av
parametrene sendes direkte videre til TGenericPicWindow (superklassen)
sin konstruktor.
PTWindowObject AParent Peker til foreldreobjektet.
LPSTR lpszCaption Peker til vindusoverskriften (vanligvis filnavnet
siden TGenericPicWindow konstruktoren lager riktig
overskrift ut av filnavnet).
HANDLE hComplexPict Handle til σ ta i mot det komplekse bildet.
OBS! Mσ vµre allokert pσ forhσnd.
BITMAPINFO *bmpInfo Peker til en klargj°rt bildestruktur.
HANDLE hBitmap Handle til et bitmap. Mσ vµre allokert pσ forhσnd!
Kodet av: MK
Modifisert: MK 20.04.92 La til st°tte for filtre (lagde brushen)
21.04.92 Lagret filterfargeverdien til systemet.
*****************************************************************************/
{
LOGBRUSH logbrush = {BS_SOLID, DB_FILTERCOLOUR, 0};
HDC hdc;
hComplex = hComplexPict;
bDirty = FALSE; // Bildet trenger forel°pig ingen oppdatering
bShowFilter = FALSE; // Ikke vis filterellipser
bButtonDown = FALSE;
bRescale = TRUE; // Trenger forel°pig ingen reskalering
iFilterType = 0; // Det er ikke filtrert
// Lager et komplekst tall = 0 til bruk ved filtrering
compZero.re = 0.0; compZero.im = 0.0;
// Husk om bildet (dvs. transformen) var sentrert
bWasShiftCentered = bShiftCenter;
// Lag penn og fyllfarge som skal brukes til filtrene og
// frihσndstegning.
hbrRed = CreateBrushIndirect((LOGBRUSH FAR *)&logbrush);
hpenRed = CreatePen(PS_SOLID, 1, DB_FILTERCOLOUR);
// Ta vare pσ hvordan fargen r°d blir representert pσ dette system
// slik at vi kan kjenne igjen fargen ved frihσndsfiltrering.
hdc = GetDC(HWindow);
rgbRed = SetPixel(hdc, 0, 0, DB_FILTERCOLOUR);
ReleaseDC(HWindow, hdc);
}
TComplexWindow::~TComplexWindow()
/****************************************************************************
Fjerner ressursene som dette komplekse bildet har brukt.
Kodet av: MK
Modifisert: MK 20.04.92 Deallokerte ogsσ den nye brushen.
*****************************************************************************/
{
if (hComplex!=NULL)
GlobalFree(hComplex);
if (hbrRed!=NULL)
DeleteObject(hbrRed);
if (hpenRed!=NULL)
DeleteObject(hpenRed);
}
void TComplexWindow::GetWindowClass(WNDCLASS& wc)
/****************************************************************************
Henter vindusklassen og standardikon for vinduet.
Kodet av: MK 28.04.92
*****************************************************************************/
{
TGenericPicWindow::GetWindowClass(wc);
wc.hIcon = LoadIcon(wc.hInstance, "COMPLEX");
}
LPSTR TComplexWindow::GetClassName()
/****************************************************************************
Returnerer vindusklassen.
Kodet av: MK 28.04.92
*****************************************************************************/
{
return "PROfft:ComplexWindow";
}
void TComplexWindow::WMSetCursor(RTMessage Msg)
/****************************************************************************
Denne velger riktig cursor hvis brukeren peker i et komplekst bilde.
Kursoren skal da vise frihσndsfilteret (en sirkel eller firkant).
RTMessage Msg Sendes videre hvis vi ikke er i vinduet klientomrσde.
Kodet av: MK 25.04.92
*****************************************************************************/
{
if (Msg.LP.Lo != HTCLIENT) // Hvis vi ikke er i klientomrσdet
{ // ikke gj°r noe spesiellt.
DefWndProc(Msg);
return;
}
// Hvis vi er i klientomrσdet, vis viskelµrcursoren
SetCursor(((TMainWindow *)Parent)->hcrRubber);
}
void TComplexWindow::CopyComplex(HANDLE hSource, HANDLE hTarget)
/****************************************************************************
Kopierer fra et komplekst bilde til et annet. Merk! Bruker dette objektet
sine bildestrukturdata. MERK! Begge handlene mσ vµre ferdig allokerte pσ
forhσnd.
HANDLE hSource Handle til orginalbildet.
HANDLE hTarget Handle til kopibildet.
Kodet av: MK 02.04.92
*****************************************************************************/
{
prcomplex huge *source, huge *destination;
int iY, iMaxY, iSize, n;
source = (prcomplex huge *)GlobalLock(hSource);
destination = (prcomplex huge *)GlobalLock(hTarget);
// Sjekk om vi fσr tak peker til bildedataene
if ((source!=NULL) && (destination!=NULL)) {
iMaxY = bmpInfo->bmiHeader.biHeight-1;
n = bmpInfo->bmiHeader.biWidth;
iSize = n*sizeof(prcomplex);
// Kopier bildet rad for rad
for (iY=0;iY<=iMaxY;iY++)
_fmemcpy(&destination[(long)(iY)*n], &source[(long)(iY)*n], iSize);
}
else
MessageBox(HWindow, "TComplexWindow::CopyComplex lock failed",
ERROR_CAPTION, MB_ERROR);
GlobalUnlock(hSource);
GlobalUnlock(hTarget);
}
BOOL TComplexWindow::ConvertComplexToBMP(HANDLE hTempComplex, HANDLE hNewBitmap)
/****************************************************************************
Denne konverterer et komplekst bilde til et bitmap bilde. Den tar
tak i den reelle delen og fors°ker σ gj°re om den til et heltall fra
0 til 255 (BYTE). Den kalles etter at brukeren har valgt og utf°rt
IFFT rett f°r programmet skal opprette et nytt TPictureWindow objekt.
HANDLE hTempComplex Handle til det komplekse bildet
HANDLE hNewBitmap Handle til bitmapbildet som skal motta data.
Kodet av: MK 23.04.92
Modifisert: MK 28.04.92 La inn "usentrering" av lave frekvenser her.
*****************************************************************************/
{
int iX, iY, iMaxX, iMaxY, iW, iH;
prcomplex rTemp;
real r;
BYTE bPixel;
BOOL bCancel;
// Opprett statusvindu
pdbProgress = new TProgressDialog(this, "PROGRESS", "Finishing IFFT");
GetApplication()->MakeWindow(pdbProgress);
SendMessage(((TProgressDialog *)pdbProgress)->HWindow,
WM_SETPROGRESSTEXT,
0, (long)((LPSTR) "Converting complex picture to bitmap picture.."));
iH = (int)(bmpInfo->bmiHeader.biHeight);
iW = (int)(bmpInfo->bmiHeader.biWidth);
iMaxX = iW-1;
iMaxY = iH-1;
r = (real)iW;
// Husker n^4, fordi vi mσ skalere ned med denne faktoren etter at
// bildet er transformert.
r = r*r*r*r;
for (iY=0;iY<=iMaxY;iY++)
{
// Vis hvor langt vi er kommet
SendMessage(pdbProgress->HWindow, WM_FIRST + WM_SETPROGRESS,
0, (((long)100*(iY))/(iMaxY)));
// Hvis brukeren avbryter, sσ slutt
if (bCancel=pdbProgress->CancelPressed())
break;
for (iX=0;iX<=iMaxX;iX++)
{
GetComplex(hTempComplex, iX, iY, iW, iH, &rTemp);
// Rund av til nµrmeste heltall
if (rTemp.re-floor(rTemp.re)>=0.5)
rTemp.re += 1; // For σ minske evt. avrundingsfeil..
// Gj°r om til en BYTE som skal inn i bitmap bildet.
bPixel = (BYTE) (rTemp.re/r);
// Hvis lave frekvenser var sentrert, gj°r om dette igjen.
if (bWasShiftCentered)
if (((iX+iY) & 1)!=0)
bPixel = 255-bPixel;
SetBMPPixel(hNewBitmap, iX, iY, iW, iH, bPixel);
}
}
DestroyWindow(pdbProgress->HWindow);
// Returnerer om denne funksjonen ble fullf°rt.
return !bCancel;
}
BOOL TComplexWindow::MakeComplexConjugate(HANDLE hComp)
/****************************************************************************
Denne klargj°r et komplekst bilde for σ ta invers transformen. Invers-
transformen bestσr av σ sende det kompleks konjugerte bildet til den
orginale FFT algortimen.
HANDLE hComp Handle til det bildet som skal klargj°res.
Kodet av: MK 23.04.92
*****************************************************************************/
{
int iX, iY, iMaxX, iMaxY, iW, iH;
prcomplex compZ1;
prcomplex huge *hpComp;
BOOL bCancel;
iW = (int)bmpInfo->bmiHeader.biWidth;
iMaxX = iW-1;
iH = (int)bmpInfo->bmiHeader.biHeight;
iMaxY = iH-1;
// Vis statusvindu
pdbProgress = new TProgressDialog(this, "PROGRESS", "Preparing for IFFT");
GetApplication()->MakeWindow(pdbProgress);
SendMessage(((TProgressDialog *)pdbProgress)->HWindow,
WM_SETPROGRESSTEXT,
0, (long)((LPSTR) "Calculating complex conjugate.."));
for (iY=0;iY<=iMaxY;iY++)
{
SendMessage(pdbProgress->HWindow, WM_FIRST + WM_SETPROGRESS,
0, (((long)100*(iY))/(iMaxY)));
if (bCancel=pdbProgress->CancelPressed())
break;
for (iX=0;iX<=iMaxX;iX++)
{
// Regn ut den komplekskonjugerte og sett denne tilbake i bildet.
GetComplex(hComp, iX, iY, iW, iH, &compZ1);
compZ1.im = -compZ1.im;
SetComplex(hComp, iX, iY, iW, iH, &compZ1);
}
}
DestroyWindow(pdbProgress->HWindow);
return !bCancel;
}
void TComplexWindow::PerformIFFT()
/****************************************************************************
Klargj°r for inverstransformen. Oppretter et midlertidig komplekst bilde
som fungerer som arbeidsbilde og et vanlig bitmapbilde som skal motta
det inverstransformerte bildet.
Kodet av: MK 23.04.92
*****************************************************************************/
{
HANDLE hTempComplex, hNewBitmap;
BITMAPINFO *bmpNewInfo;
PTWindowsObject ptTemp;
BOOL bOK;
GlobalCompact(-1); // Rydd opp f°r vi fors°ker σ allokere minne
// Fors°ker σ allokere plass til et midlertidig arbeidsbilde
hTempComplex = GlobalAlloc(GMEM_PROFFTDATA,
bmpInfo->bmiHeader.biWidth*bmpInfo->bmiHeader.biHeight
*sizeof(prcomplex)+MS_BUG);
// Allokerer plass til bitmapbildet som skal motta inverstransformen.
hNewBitmap = GlobalAlloc(GMEM_PROFFTDATA,
bmpInfo->bmiHeader.biSizeImage+MS_BUG);
if ((hTempComplex != NULL) && (hNewBitmap!=NULL))
{
// Oppretter en midlertidig arbeidskopi av det komplekse bildet
CopyComplex(hComplex, hTempComplex);
// Hvis brukeren ikke avbryter klargj°ringen..
if (bOK=MakeComplexConjugate(hTempComplex))
{
// Utf°r inverstransformen (dvs. transformen med kompleks
// konjugerte inndata).
if (bOK=FFT(hTempComplex))
{
// Hvis brukeren ikke avbr°t sσ konverter til et BMP bilde
bOK = ConvertComplexToBMP(hTempComplex, hNewBitmap);
}
}
GlobalFree(hTempComplex); // Frigj°r det midlertidige arbeidsbildet (komplekst)
// Lager en kopi av bildestrukturdataene
if (bOK)
{
// Hvis brukeren ikke avbr°t..
bmpNewInfo = MakeDuplicateBMPInfo(bmpInfo);
// Opprett et nytt bitmap barnevindu (TPictureWindow) objekt
((TMainWindow *)Parent)->CreateChild(FileName, bmpNewInfo, hNewBitmap);
}
}
else
{
MessageBox(HWindow, "IFFT: Not enough memory for new complex/bitmap picture", ERROR_CAPTION, MB_ERROR);
bOK = FALSE;
}
if (!bOK)
{
// Deallokerer minne hvis funksjonen ikke ble fullf°rt.
GlobalFree(hTempComplex);
GlobalFree(hNewBitmap);
}
}
void TComplexWindow::PerformFFT()
/****************************************************************************
Klargj°r for fouriertransformen. Konverterer bitmap bildet til et komplekst
bilde som det sσ utf°res fouriertransformen pσ.
Kodet av: MK 23.04.92
*****************************************************************************/
{
if (ConvertBMPToComplex(hBitmap, hComplex))
{
// Hvis brukeren ikke avbr°t konvertering, utf°r FFT
if (FFT(hComplex))
{
// Ber det komplekse bilde regne og vise sin amp. representasjon
bDirty = TRUE;
InvalidateRect(HWindow, NULL, FALSE);
}
else
CloseWindow();
}
else
CloseWindow();
}
BOOL TComplexWindow::FFT(HANDLE hTarget)
/****************************************************************************
Utf°rer fouriertransformen. Denne rutinen kan ogsσ brukes til invers-
transformen ved at man fikser litt pσ inndataene (se PerformIFFT()).
MERK! Bruker dette objektet sine bildestrukturdata.
HANDLE hTarget Handle til det komplekse bildet som FFT skal utf°res pσ.
Kodet av: MK 03.04.92
Oppdatert: MK 23.04.92 Klargjort for inverstransformen ved at den
tar et komplekst bilde som parameter.
*****************************************************************************/
{
int n, iX, iY, iW, iH, iTest;
prcomplex *z1, *z2, *ptfft, compZ;
int iSize, iRet, iPixel, iMaxY, iMaxX;
char acMessage[40];
prcomplex huge *hpComplexPict;
BOOL bCancel;
bCancel = FALSE;
hpComplexPict = (prcomplex huge *)GlobalLock(hTarget);
if (hpComplexPict!=NULL)
{
iH = (int)(bmpInfo->bmiHeader.biHeight);
iMaxY = iH-1;
iW = (int)(bmpInfo->bmiHeader.biWidth);
iMaxX = iW - 1;
n = iW;
iSize = sizeof(prcomplex)*n;
// Klargj°r statusvindu
pdbProgress = new TProgressDialog(this, "PROGRESS", "FFT/IFFT progress"); //M
GetApplication()->MakeWindow(pdbProgress);
// Allokerer arbeidsbuffere til FFT
z1 = (prcomplex*) malloc(iSize);
if (z1!=NULL)
{
z2 = (prcomplex*) malloc(iSize);
if (z2!=NULL)
{
SendMessage(pdbProgress->HWindow,
WM_FIRST + WM_SETPROGRESSTEXT,
0, (long)((LPSTR) "Transforming rows.."));
// Transformerer radvis
for (iY=0;iY<=iMaxY;iY++)
{
SendMessage(pdbProgress->HWindow, WM_FIRST + WM_SETPROGRESS,
0, (((long)100*(iY))/(2*iMaxY)));
if (bCancel=pdbProgress->CancelPressed())
break;
// Kopier fra bildet inn i arbeidsomrσdet
_fmemcpy(z1, &hpComplexPict[((long)(iY))*n], iSize);
// Kj°r den diskrete 1D transformen
iRet = fft(z1, z2, n);
if (iRet==0)
{
MessageBox(HWindow, "FFT: Transform failed. Out of memory",
ERROR_CAPTION, MB_ERROR);
bCancel = TRUE;
break;
}
else
{
if (iRet==1)
ptfft = z1;
else
ptfft = z2;
// Multipliserer hver rekke med n if°lge algoritmen for 2D-FFT
for (iX=0;iX<=iMaxX;iX++)
{
ptfft[iX].re *= (real)n;
ptfft[iX].im *= (real)n;
}
// Kopiererer den transformerte rekka tilbake i det komplekse bildet
_fmemcpy(&hpComplexPict[((long)(iY))*n], ptfft, iSize);
}
}
if (!bCancel)
{
SendMessage(pdbProgress->HWindow,
WM_FIRST + WM_SETPROGRESSTEXT,
0, (long)((LPSTR) "Transforming columns.."));
// Transformerer kolonnevis
for (iX=0;iX<=iMaxX;iX++)
{
SendMessage(pdbProgress->HWindow, WM_FIRST + WM_SETPROGRESS,
0, 50+(((long)100*(iX))/(2*iMaxX)));
if (bCancel=pdbProgress->CancelPressed())
break;
for (iY=0;iY<=iMaxY;iY++)
{
GetComplex(hTarget, iX, iY, iW, iH, &z1[iY]);
}
// Kj°r den diskrete 1D transformen
iRet = fft(z1, z2, n);
if (iRet==0)
{
MessageBox(HWindow, "FFT: Transform failed. Out of memory",
ERROR_CAPTION, MB_ERROR);
bCancel = TRUE;
break;
}
else
{
if (iRet==1)
ptfft = z1;
else
ptfft = z2;
// Kopierer tilbake fra arbeidsomrσdet
for (iY=0;iY<=iMaxY;iY++)
{
SetComplex(hTarget, iX, iY, iW, iH, &ptfft[iY]);
}
}
}
}
}
else
{
MessageBox(HWindow, "FFT: Out of memory",
ERROR_CAPTION, MB_ERROR);
bCancel = TRUE;
}
free(z2);
}
else
{
MessageBox(HWindow, "FFT: Out of memory",
ERROR_CAPTION, MB_ERROR);
bCancel = TRUE;
}
free(z1);
GlobalUnlock(hTarget);
DestroyWindow(pdbProgress->HWindow);
}
else
MessageBox(HWindow, "TComplexWindow::TComplexWindow lock failed",
ERROR_CAPTION, MB_ERROR);
return !bCancel;
}
BOOL TComplexWindow::ConvertBMPToComplex(HANDLE hSourceBitmap, HANDLE hTargetComplex)
/****************************************************************************
Konverterer fra et BMP bilde til et komplekst bildet. Merk! Denne algoritmen
er skrevet med tanke pσ hastighet, ikke lesbarhet. Bruker tabelloppslag i
steden for utregning fra BYTE til komplekse tall. MERK! Begge bildene mσ
vµre allokert pσ forhσnd!
HANDLE hSourceBitmap Handle til Bitmapbildet som skal konverteres
HANDLE hTargetComplex Komplekst bilde som mottar konverteringen.
Kodet av: MK 01.04.92
Oppdatert: MK 04.04.92 Bygget om for tabelloppslag.
*****************************************************************************/
{
int iX, iY, iPixel, iMaxX, iMaxY, iW, iH;
prcomplex compZ, far *prByteToComplex;
TProgressDialog *pdbProgress;
LPSTR lpBitmap, lpComplex;
BYTE b;
BOOL bCancel;
lpBitmap = GlobalLock(hSourceBitmap);
lpComplex = GlobalLock(hTargetComplex);
if ((lpBitmap!=NULL) && (lpComplex!=NULL))
{
iW = (int)(bmpInfo->bmiHeader.biWidth);
iMaxX = iW - 1;
iH = (int)(bmpInfo->bmiHeader.biHeight);
iMaxY = iH - 1;
pdbProgress = new TProgressDialog(this, "PROGRESS", "Converting bitmap to complex");
GetApplication()->MakeWindow(pdbProgress);
SendMessage(((TProgressDialog *)pdbProgress)->HWindow,
WM_SETPROGRESSTEXT,
0, (long)((LPSTR) "Creating complex picture.."));
prByteToComplex = (prcomplex far *)GlobalLock(hByteToComplexTable);
if (prByteToComplex!=NULL)
{
for (iY=0;iY<=iMaxY;iY++)
{
SendMessage(pdbProgress->HWindow, WM_SETPROGRESS,
0, (((long)100*(iY))/(iMaxY)));
if (bCancel=pdbProgress->CancelPressed())
break;
for (iX=0;iX<=iMaxX;iX++)
{
iPixel = (int)GetBMPPixel(hSourceBitmap, iX, iY, iW, iH);
// Tabelloppslag for rask konvertering
compZ = prByteToComplex[iPixel];
if (bWasShiftCentered)
if (((iX+iY) & 1)!=0)
compZ.re = -compZ.re;
SetComplex(hTargetComplex, iX, iY, iW, iH, &compZ);
}
}
GlobalUnlock(hByteToComplexTable);
}
else
MessageBox(GetActiveWindow(), "ConvertBMPToComplex prByteToComplex==NULL",
ERROR_CAPTION, MB_ERROR);
GlobalUnlock(hSourceBitmap);
GlobalUnlock(hTargetComplex);
DestroyWindow(pdbProgress->HWindow);
}
else
MessageBox(GetActiveWindow(), "ConvertBMPToComplex locks failed",
ERROR_CAPTION, MB_ERROR);
return !bCancel;
}
BOOL TComplexWindow::UpdateBitmap()
/****************************************************************************
Denne rutinen kalles fra TComplexWindow::Paint og tar seg av reskalering
(hvis n°dvendig) av amplitudeverdiene og tegner bitmaprepresentasjonen inn
i bitmap bildet. Merk! Delen som regner ut maks/min amplitude er skrevet
for hastighet ikke for lettlesbarhet (leser parvis, sammenligner minste
mot minste verdi, st°rste mot st°rste verdi => 3/2*n algoritme).
Kodet av: MK 03.04.92
*****************************************************************************/
{
int iX, iY, iMaxY, iMaxX, iW, iH;
long lValue;
prcomplex compZ1, compZ2;
BYTE bPixel;
real rLogAmplitude1, rLogAmplitude2;
real rScale;
char acMessage[40];
BOOL bCancel;
if (LockBMP())
{
if (LockComplex())
{
bCancel = FALSE;
pdbProgress = new TProgressDialog(this, "PROGRESS", "Updating amplitude representation");
GetApplication()->MakeWindow(pdbProgress);
iH = (int)(bmpInfo->bmiHeader.biHeight);
iW = (int)(bmpInfo->bmiHeader.biWidth);
iMaxX = iW - 1;
iMaxY = iH - 1;
// Hvis det trengs reskalering. Merk! Ved bruk av filtre settes
// ikke denne til TRUE, fordi bitmaprepresentasjonen bruker minste
// amplitude = svart. Da blir det et stor mellomrom mellom 0
// og den minste verdien, som ville spist verdifull informasjon i
// bildet hvis vi hadde foretatt reskalering.
if (bRescale)
{
SendMessage(pdbProgress->HWindow,
WM_SETPROGRESSTEXT,
0, (long)((LPSTR) "Rescaling amplitude grayscales.."));
MaxLogAmplitude = MINREAL;
MinLogAmplitude = MAXREAL;
for (iY=0;iY<=iMaxY;iY++)
{
SendMessage(pdbProgress->HWindow, WM_SETPROGRESS,
0, (((long)100*(iY))/(2*iMaxY)));
if (bCancel=pdbProgress->CancelPressed())
break;
iX = 0;
while (iX<=iMaxX)
{
GetComplex(hComplex, iX++, iY, iW, iH, &compZ1);
GetComplex(hComplex, iX++, iY, iW, iH, &compZ2);
rLogAmplitude1 = FFTLOG(1+sqrt(compZ1.re*compZ1.re+compZ1.im*compZ1.im));
rLogAmplitude2 = FFTLOG(1+sqrt(compZ2.re*compZ2.re+compZ2.im*compZ2.im));
if (rLogAmplitude1<=rLogAmplitude2)
{
if (rLogAmplitude1<MinLogAmplitude)
MinLogAmplitude = rLogAmplitude1;
if (rLogAmplitude2>MaxLogAmplitude)
MaxLogAmplitude = rLogAmplitude2;
}
else
{
if (rLogAmplitude2<MinLogAmplitude)
MinLogAmplitude = rLogAmplitude2;
if (rLogAmplitude1>MaxLogAmplitude)
MaxLogAmplitude = rLogAmplitude1;
}
}
}
}
if (!bCancel)
{
SendMessage(pdbProgress->HWindow,
WM_FIRST + WM_SETPROGRESSTEXT,
0, (long)((LPSTR) "Plotting new grayscales.."));
rScale = MaxLogAmplitude - MinLogAmplitude;
rScale = 255/rScale;
for (iY=0;iY<=iMaxY;iY++)
{
// Tar hensyn til om reskalering er foretatt nσr
// den viser % av jobben som er ferdig.
if (!bRescale)
lValue = ((long)100*iY)/iMaxY;
else
lValue = 50+(((long)100*(iY))/(2*iMaxY));
SendMessage(pdbProgress->HWindow, WM_SETPROGRESS, 0, lValue);
if (bCancel=pdbProgress->CancelPressed())
break;
// Konverterer og skalerer
for (iX=0;iX<bmpInfo->bmiHeader.biWidth;iX++)
{
GetComplex(hComplex, iX, iY, iW, iH, &compZ1);
rLogAmplitude1 = FFTLOG(1+sqrt(compZ1.re*compZ1.re+compZ1.im*compZ1.im));
bPixel = (BYTE)(rScale*(rLogAmplitude1-MinLogAmplitude));
SetBMPPixel(hBitmap, iX, iY, iW, iH, bPixel);
}
}
}
UnlockComplex();
bDirty = FALSE;
DestroyWindow(pdbProgress->HWindow);
}
else
MessageBox(HWindow, "TComplexWindow::UpdateBitmap LockComplex failed",
ERROR_CAPTION, MB_OK);
UnlockBMP();
}
else
MessageBox(HWindow, "TComplexWindow::UpdateBitmap LockBitmap failed",
ERROR_CAPTION, MB_OK);
return !bCancel;
}
void TComplexWindow::Paint(HDC, PAINTSTRUCT& PaintInfo)
/****************************************************************************
Viser det komplekse vinduet sin logaritmiske amplituderepresentasjon.
Tar ogsσ og tegner de aktuelle filtrene hvis brukeren holder pσ σ velge
filterradius.
PAINTSTRUCT& PaintInfo Omrσde som trenger σ tegnes.
Kodet av: MK 01.04.92
Oppdatert: MK 23.04.92 Support for filtre.
*****************************************************************************/
{
HDC MemoryDC;
HANDLE OldBitmapHandle;
RECT ClientRect;
HRGN hrgn[4];
int i, iMiddle, iW, iLow, iUp;
int x11, y11, x12, y12, x21, y21, x22, y22;
if (hBitmap)
{
// Velg riktig palette.
SelectPalette(PaintInfo.hdc, ((TMainWindow *)Parent)->hPal, 0);
SetMapMode(PaintInfo.hdc, MM_TEXT);
// Hvis bitmap bildet er forandret mσ vi oppdatere vindusrepr.
if (bDirty)
if (!UpdateBitmap())
// Hvis brukeren velger avbryt sσ lukk vinduet.
PostMessage(HWindow, WM_CLOSE, 0, 0);
if (LockBMP())
{
// Tegn ut DeviceIndependent bitmappen pσ bildeflaten
SetDIBitsToDevice(PaintInfo.hdc, 0, 0,
bmpInfo->bmiHeader.biWidth, bmpInfo->bmiHeader.biHeight,
0, 0, 0, bmpInfo->bmiHeader.biHeight,
&hpBitmap[0], bmpInfo, DIB_RGB_COLORS);
// Hvis filtrene skal vises (nσr vi er inne og velger radius
// i de forskjellige filtrene) sσ vis disse.
if (bShowFilter)
{
for(i=0;i<4;i++)
hrgn[i]=NULL;
// Regner ut "boksen" som den innerste sirkelen skal tegnes i
iW = (int)(bmpInfo->bmiHeader.biWidth);
iLow = iLowerValue+1;
iUp = iUpperValue+1;
iMiddle = iW / 2;
x11 = iMiddle - iLow;
y11 = iMiddle - iLow;
x12 = iW - (iMiddle - iLow);
y12 = iW - (iMiddle - iLow);
x11++; y11++;
// Hvis vi har et filter med to radiuser, regn ut den andre boksen
// i tillegg
if ((iFilterType==CM_FILTERBANDPASS) || (iFilterType==CM_FILTERBANDSTOP))
{
x21 = iMiddle - iUp;
y21 = iMiddle - iUp;
x22 = iW - (iMiddle - iUp);
y22 = iW - (iMiddle - iUp);
x21++;y21++;
}
// Ut i fra de forskjellige filtertypene velger vi hva som skal
// tegnes i r°dt.
switch (iFilterType)
{
case CM_FILTERHIGHPASS:
case CM_FILTERBWHIGHPASS:
hrgn[2] = CreateEllipticRgn(x11, y11, x12, y12);
break;
case CM_FILTERLOWPASS:
case CM_FILTERBWLOWPASS:
hrgn[0] = CreateEllipticRgn(x11, y11, x12, y12);
hrgn[1] = CreateRectRgn(0, 0, iW, iW);
hrgn[2] = CreateRectRgn(0, 0, iW, iW);
CombineRgn(hrgn[2], hrgn[0], hrgn[1], RGN_XOR);
DeleteObject(hrgn[0]);
DeleteObject(hrgn[1]);
break;
case CM_FILTERBANDSTOP:
hrgn[0] = CreateEllipticRgn(x21, y21, x22, y22);
hrgn[1] = CreateEllipticRgn(x11, y11, x12, y12);
hrgn[2] = CreateRectRgn(0, 0, iW, iW);
CombineRgn(hrgn[2], hrgn[0], hrgn[1], RGN_XOR);
DeleteObject(hrgn[0]);
DeleteObject(hrgn[1]);
break;
case CM_FILTERBANDPASS:
hrgn[0] = CreateEllipticRgn(x21, y21, x22, y22);
hrgn[1] = CreateEllipticRgn(x11, y11, x12, y12);
hrgn[3] = CreateRectRgn(0, 0, iW, iW);
CombineRgn(hrgn[3], hrgn[0], hrgn[1], RGN_XOR);
DeleteObject(hrgn[0]);
DeleteObject(hrgn[1]);
hrgn[0] = CreateRectRgn(0, 0, iW, iW);
hrgn[2] = CreateRectRgn(0, 0, iW, iW);
CombineRgn(hrgn[2], hrgn[0], hrgn[3], RGN_XOR);
DeleteObject(hrgn[0]);
DeleteObject(hrgn[3]);
break;
}
hrgn[0]=CreateRectRgn(0, 0, iW, iW);
hrgn[3]=CreateRectRgn(0, 0, iW, iW);
CombineRgn(hrgn[3], hrgn[0], hrgn[2], RGN_AND);
// Tegn det endelige omrσdet i r°dt.
FillRgn(PaintInfo.hdc, hrgn[3], hbrRed);
// Fjern de allokerte regionene, de er bare midlertidige
for(i=0;i<4;i++)
if (hrgn[i]!=NULL)
DeleteObject(hrgn[i]);
}
ValidateRect(HWindow, NULL);
UnlockBMP();
}
else
MessageBox(HWindow, "TComplexWindow::Paint LockBitmap failed", ERROR_CAPTION, MB_ERROR);
}
}
BOOL TComplexWindow::LockComplex()
/****************************************************************************
Locker det komplekse bildet og lagrer en huge pointer til det.
Returnerer: TRUE hvis det lot seg lock
FALSE ellers
Kodet av: MK
*****************************************************************************/
{
hpComplex = (prcomplex huge *)GlobalLock(hComplex);
if (hpComplex!=NULL)
return TRUE;
else
return FALSE;
}
void TComplexWindow::UnlockComplex()
/****************************************************************************
Unlocker det komplekse bildet (hpComplex ikke lenger brukbar).
Kodet av: MK 19.04.92
*****************************************************************************/
{
GlobalUnlock(hComplex);
}
void TComplexWindow::WMMDIActivate(RTMessage Msg)
/****************************************************************************
Denne kalles nσr bildet aktiveres. S°rger for σ sette de menyvalgene
som er aktuelle for dette bildet (dvs. enabler FFT, filtre o.l.).
RTMessage Msg Sendes videre til superklassen.
Kodet av: MK
*****************************************************************************/
{
TGenericPicWindow::WMMDIActivate(Msg);
if (Msg.WParam)
{
SetMenuItems(MF_ENABLED);
}
else
SetMenuItems(MF_GRAYED);
}
void TComplexWindow::SetMenuItems(WORD wStatus)
/****************************************************************************
Setter de aktuelle valgene for dette objektet.
WORD wStatus Inneholder hva valgene skal settes til (MF_ENABLED/MF_GRAYED)
Kodet av: MK
*****************************************************************************/
{
HMENU hMenu;
int i;
hMenu=GetMenu(((TMainWindow *)Parent)->HWindow);
if (bWasShiftCentered)
for (i=CM_FILTERLOWPASS;i<CM_FILTERFREEHAND;i++)
EnableMenuItem(hMenu, i, wStatus);
EnableMenuItem(hMenu, CM_FILTERFREEHAND, wStatus);
EnableMenuItem(hMenu, CM_TRANSIFFT, wStatus);
EnableMenuItem(hMenu, CM_EDITCOPY, wStatus);
EnableMenuItem(hMenu, CM_EDITCUT, wStatus);
EnableMenuItem(hMenu, CM_FILESAVEAS, wStatus);
}
void TComplexWindow::PrepareToExecuteFilter()
/****************************************************************************
Klargj°r filterfunksjonen ved σ opprette en kopi av det aktive
TComplexWindow og be dette filtrere seg selv ut i fra de parametre
brukeren har valgt. Denne blir kallt uansett filtertype (ogsσ frihσnds-
filteret).
Kodet av: MK 22.04.92
*****************************************************************************/
{
int iW, iH;
HANDLE hNewComplex;
HANDLE hNewBitmap;
BITMAPINFO *bmpNewInfo;
TComplexWindow *ptNewComp;
HBITMAP hTempBitmap;
HDC hdc, hdcMem;
GlobalCompact(-1); // Rydd opp f°r en fors°ker σ allokere minne
// Alloker minne til et nytt komplekst bilde.
hNewComplex = GlobalAlloc(GMEM_PROFFTDATA,
bmpInfo->bmiHeader.biWidth*bmpInfo->bmiHeader.biHeight
*sizeof(prcomplex)+MS_BUG);
if (hNewComplex!=NULL)
{
// Kopier dataene i det komplekse bildet over i det nye.
CopyComplex(hComplex, hNewComplex);
// Lag en kopi av bildestrukturdataene
bmpNewInfo = MakeDuplicateBMPInfo(bmpInfo);
if (bmpNewInfo!=NULL)
{
// Alloker minne til et nytt bitmapbilde
hNewBitmap = GlobalAlloc(GMEM_PROFFTDATA,
bmpNewInfo->bmiHeader.biSizeImage+MS_BUG);
if (hNewBitmap!=NULL)
{
// Kopier bitmap dataene over i det nye bildet
CopyBMP(hBitmap, hNewBitmap);
iW = (int)bmpInfo->bmiHeader.biWidth;
iH = (int)bmpInfo->bmiHeader.biHeight;
// Vis filterparametrene (dvs. sirklene som viser radius)
bShowFilter = TRUE;
UpdateWindow(HWindow);
// Opprett en tegneflate som inneholder en bildekopi
// av filteret som er valgt. Brukes kun av frihσndsfilteret.
hdc = GetDC(HWindow);
hdcMem = CreateCompatibleDC(hdc);
hTempBitmap = CreateCompatibleBitmap(hdc, iW, iH);
if (hTempBitmap!=NULL)
{
// Kopier dataene fra vinduets klientomrσde over i vσrt buffer.
SelectObject(hdcMem, hTempBitmap);
BitBlt(hdcMem, 0, 0, iW, iH, hdc, 0, 0,SRCCOPY);
// Opprett det nye TComplexWindow objektet
bShowFilter = FALSE;
InvalidateRect(HWindow, NULL, FALSE);
ptNewComp=((TComplexWindow *)(((TMainWindow *)Parent)->CreateComplexChild(FileName, hNewComplex,
bmpNewInfo, hNewBitmap)));
// La det nye arve noen parametre fra det gamle
ptNewComp->iLowerValue=iLowerValue;
ptNewComp->iUpperValue=iUpperValue;
ptNewComp->iFilterType=iFilterType;
ptNewComp->bDirty=FALSE;
ptNewComp->MinLogAmplitude=MinLogAmplitude;
ptNewComp->MaxLogAmplitude=MaxLogAmplitude;
// Vis det nye
UpdateWindow(ptNewComp->HWindow);
// Be det nye filtrere seg selv
ptNewComp->ExecuteFilter(hdcMem);
}
else
MessageBox(HWindow, "Filter: Not enough memory to allocate scratchpicture",
ERROR_CAPTION, MB_ERROR);
ReleaseDC(HWindow, hdc);
DeleteDC(hdcMem);
DeleteObject(hTempBitmap);
}
else
MessageBox(HWindow, "Filter: Not enough memory to allocate new bitmap picture",
ERROR_CAPTION, MB_ERROR);
}
else
MessageBox(HWindow, "TPictureWindow::FFT bmpNewInfo==NULL",
ERROR_CAPTION, MB_ERROR);
}
else
MessageBox(HWindow, "Filter: Not enough memory to allocate new complex picture",
ERROR_CAPTION, MB_ERROR);
}
void TComplexWindow::ExecuteFilter(HDC hdcMem)
/****************************************************************************
Utf°rer selve filtreringen i det aktuelle objektet.
HDC hdcMem En bildeflate som inneholder r°dfargen hvis det dreier
seg om frihσndsfilteret.
Kodet av: MK 22.04.92
*****************************************************************************/
{
int iX, iY, iMaxX, iMaxY, iW, iH;
real rDistance, rH, rBWDistance, rTemp;
real rMiddleX, rMiddleY, rT1, rT2;
prcomplex huge *hpComp;
BOOL bCancel, bRemove;
char acTemp[50];
HDC hdc;
prcomplex comp;
iW = (int)bmpInfo->bmiHeader.biWidth;
iH = (int)bmpInfo->bmiHeader.biHeight;
hdc = GetDC(HWindow);
iMaxX = iW-1;
iMaxY = iH-1;
pdbProgress = new TProgressDialog(this, "PROGRESS", "Filter progress");
GetApplication()->MakeWindow(pdbProgress);
SendMessage(((TProgressDialog *)pdbProgress)->HWindow,
WM_SETPROGRESSTEXT,
0, (long)((LPSTR) "Filtering.."));
// Finn midtpunktet i bildet
rMiddleX = ((real)iMaxX)/2;
rMiddleY = ((real)iMaxY)/2;
rBWDistance=(real)iLowerValue;
for (iY=0;iY<=iMaxY;iY++)
{
SendMessage(pdbProgress->HWindow, WM_FIRST + WM_SETPROGRESS,
0, (((long)100*(iY))/(iMaxY)));
if (bCancel=pdbProgress->CancelPressed())
break;
for (iX=0;iX<=iMaxX;iX++)
{
// L°kkene over gσr gjennom alle punktene i bildet.
// bRemove forteller om det aktuelle punktet skal fjernes
// fra frekvensplanet.
bRemove = FALSE;
// Hvis det dreier seg om noen av de filtreren som bruker
// radius som parametre (dvs. alle bortsett fra frihσnd)
if (iFilterType!=CM_FILTERFREEHAND)
{
// Regn ut avstand fra et punkt i bildet til midten.
rT1 = (float)iX-rMiddleX;
rT2 = (float)iY-rMiddleY;
rDistance = (real)sqrt(rT1*rT1+rT2*rT2);
// Ut i fra hva slags filtertype det dreier seg om, sjekk
// avstanden og sett bRemove hvis denne skal fjernes.
switch (iFilterType)
{
case CM_FILTERLOWPASS:
if (rDistance>(real)iLowerValue)
bRemove=TRUE;
break;
case CM_FILTERHIGHPASS:
if (rDistance<(real)iLowerValue)
bRemove=TRUE;
break;
case CM_FILTERBANDSTOP:
if ((rDistance>(real)iLowerValue) && (rDistance<(real)iUpperValue))
bRemove=TRUE;
break;
case CM_FILTERBANDPASS:
if (!((rDistance>(real)iLowerValue) && (rDistance<(real)iUpperValue)))
bRemove=TRUE;
break;
case CM_FILTERBWLOWPASS:
// Butterworth filtrene hσndteres spesiellt, her skal
// alle punktene forandres ut i fra en formel.
GetComplex(hComplex, iX, iY, iW, iH, &comp);
if (rDistance!=0)
{
rTemp = rBWDistance/rDistance;
rH = 1/(1+rTemp*rTemp);
}
else
rH = 0;
comp.re *= rH;
comp.im *= rH;
SetComplex(hComplex, iX, iY, iW, iH, &comp);
break;
case CM_FILTERBWHIGHPASS:
// Butterworth filtrene hσndteres spesiellt, her skal
// alle punktene forandres ut i fra en formel.
GetComplex(hComplex, iX, iY, iW, iH, &comp);
if (rBWDistance!=0)
{
rTemp = rDistance/rBWDistance;
rH = 1/(1+rTemp*rTemp);
}
else
rH = 0;
comp.re *= rH;
comp.im *= rH;
SetComplex(hComplex, iX, iY, iW, iH, &comp);
break;
}
}
else
// Hvis vi kommer hit dreier det seg om frihσndsfilteret
// Vi leser fargen i bildet som representerer den r°dfargen
// vi brukte og tegne med. Hvis disse matcher skal dette
// punktet fjernes i det komplekse bildet.
if (GetPixel(hdcMem, iX, iY)==rgbRed)
bRemove = TRUE;
// Hvis et punkt skal vekk, fjern det i det komplekse,
// i bitmappen og pσ skjermen.
if (bRemove)
{
SetPixel(hdc, iX, iY, 0L);
SetComplex(hComplex, iX, iY, iW, iH, &compZero);
SetBMPPixel(hBitmap, iX, iY, iW, iH, 0);
}
}
}
ReleaseDC(HWindow, hdc);
DestroyWindow(pdbProgress->HWindow);
// Hvis brukeren ikke har avbrutt filteroperasjonen..
if (!bCancel)
{
// Ikke vis filterellipsene
bShowFilter = FALSE;
// Hvis det dreier seg om et butterworth filter mσ vi reskalere hele
// bildet siden alle punktene i bildet blir forandret.
if ((iFilterType==CM_FILTERBWLOWPASS) || (iFilterType==CM_FILTERBWHIGHPASS))
{
bDirty = TRUE;
bRescale = TRUE;
}
else
// Hvis ikke °nsker vi ikke σ reskalere bildet..
{
bRescale = FALSE;
bDirty = FALSE;
}
// Gi vinduet beskjed om σ oppdatere seg selv.
InvalidateRect(HWindow, NULL, FALSE);
}
// Hvis brukeren har avbrutt filteroperasjonen, fjern dette
// TComplexWindow objektet.
else
PostMessage(HWindow, WM_CLOSE, 0, 0);
}